package com.hmall.gateway.filters;

import com.hmall.gateway.config.AuthProperties;
import com.hmall.gateway.utils.JwtTool;
import lombok.RequiredArgsConstructor;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.util.List;

//@EnableConfigurationProperties(AuthProperties.class) 使用这个注解，会自动将 AuthProperties 注入到 AuthGlobalFilter 中

@Component
@RequiredArgsConstructor
@EnableConfigurationProperties(AuthProperties.class)
public class AuthGlobalFilter implements GlobalFilter, Ordered {


    // 1, 请求 路径匹配器对象，用来校验请求url 是否包含在 白名单中

    private  AntPathMatcher  antPathMatcher = new AntPathMatcher();


    // 2,获取请求的路径的 白名单

    private  final  AuthProperties authProperties;


    // 3,jwt 工具
    private final JwtTool jwtTool;
    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        // 1,获取 请求 和 响应的参数对象
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();

        // 2. 先从请求中 获取请求路径，看是否在 白名单中
        String path = request.getPath().toString();


        List<String> excludePaths = authProperties.getExcludePaths();
        for (String excludePath : excludePaths) {
            boolean match = antPathMatcher.match(excludePath, path);
            if (match) {
                // 3. 如果在白名单中，则直接放行
                return chain.filter(exchange);
            }
        }

        // 3, 如果不在白名单中，则需要获取token 并 校验token
        
        // 3.1 获取token,获取第一个即可
        String token = request.getHeaders().getFirst("Authorization");
        // 3.2 判断token 是否为空
        if(token==null){
        //     返回1个 401 状态码。并拦截
            response.setStatusCode(HttpStatus.UNAUTHORIZED);

        //     拦截
          return   response.setComplete();

        }

        // 3.3 校验token
        Long userId = null;
        try {
            userId = jwtTool.parseToken(token);
        } catch (Exception e) {
            // 校验失败
            e.printStackTrace();
            response.setStatusCode(HttpStatus.UNAUTHORIZED);
            // 拦截
            return response.setComplete();
        }

        /* 此时还有问题，就是我们的 微服务中 如何共享 线程的局部变量？ 所以我们要把 解析出来的 token,再放在1个请求头中
        然后在common 公共模块中，定义一个类，UserContext，里面定义一个静态的线程局部变量，用来保存当前线程的局部变量，
        这样多个微服务之间就可以共享 token 信息了
        * */

        request.mutate().header("user-info",userId.toString());


        // 放行
        return chain.filter(exchange);

    }

    // 决定拦截器的执行顺序，值越小越先执行
    @Override
    public int getOrder() {
        return 0;
    }
}
